using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Globalization;

namespace MSHelpLib.BaseCode
{
	/// <summary>
	/// The class <c>BinaryReaderHelp</c> implements static helper methods for extracting binary data 
	/// from a binary reader object.
	/// </summary>
	internal class BinaryReaderHelp
	{
		/// <summary>
		/// Internal helper method to extract null-terminated strings from a binary reader
		/// </summary>
		/// <param name="binReader">reference to the binary reader</param>
		/// <param name="offset">offset in the stream</param>
		/// <param name="noOffset">true if the offset value should be used</param>
		/// <param name="encoder">encoder used for text encoding</param>
		/// <returns>An extracted string value</returns>
		internal static string ExtractString(ref BinaryReader binReader, int offset, bool noOffset, Encoding encoder)
		{
			string strReturn = "";

			if(encoder == null)
				encoder = Encoding.ASCII;

			ArrayList nameBytes = new ArrayList();
			byte curByte;
			
			if(!noOffset)
				binReader.BaseStream.Seek(offset, SeekOrigin.Begin);

			if(binReader.BaseStream.Position >= binReader.BaseStream.Length)
				return "";

			curByte = binReader.ReadByte();
			while( (curByte != (byte)0) && (binReader.BaseStream.Position < binReader.BaseStream.Length) )
			{	
				nameBytes.Add( curByte );
				curByte = binReader.ReadByte();
			}

			byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));
			strReturn = encoder.GetString(name,0,name.Length);

			return strReturn;
		}

		/// <summary>
		/// Internal helper method to extract a string with a specific length from the binary reader
		/// </summary>
		/// <param name="binReader">reference to the binary reader</param>
		/// <param name="length">length of the string (number of bytes)</param>
		/// <param name="offset">offset in the stream</param>
		/// <param name="noOffset">true if the offset value should be used</param>
		/// <param name="encoder">encoder used for text encoding</param>
		/// <returns>An extracted string value</returns>
		internal static string ExtractString(ref BinaryReader binReader, int length, int offset, bool noOffset, Encoding encoder)
		{
			string strReturn = "";

			if(length == 0)
				return "";

			if(encoder == null)
				encoder = Encoding.ASCII;

			ArrayList nameBytes = new ArrayList();
			byte curByte;
			
			if(!noOffset)
				binReader.BaseStream.Seek(offset, SeekOrigin.Begin);

			if(binReader.BaseStream.Position >= binReader.BaseStream.Length)
				return "";

			curByte = binReader.ReadByte();
			while( (curByte != (byte)0) && (nameBytes.Count < length) && (binReader.BaseStream.Position < binReader.BaseStream.Length) )
			{	
				nameBytes.Add( curByte );

				if(nameBytes.Count < length)
					curByte = binReader.ReadByte();
			}

			byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));
			strReturn = encoder.GetString(name,0,name.Length);

			return strReturn;
		}

		/// <summary>
		/// Internal helper method to extract a string with a specific length from the binary reader
		/// </summary>
		/// <param name="binReader">reference to the binary reader</param>
		/// <param name="bFoundTerminator">reference to a bool vairable which will receive true if the
		/// string terminator \0 was found. false indicates that the end of the stream was reached.</param>
		/// <param name="offset">offset in the stream</param>
		/// <param name="noOffset">true if the offset value should be used</param>
		/// <param name="encoder">encoder used for text encoding</param>
		/// <returns>An extracted string value</returns>
		internal static string ExtractString(ref BinaryReader binReader, ref bool bFoundTerminator, int offset, bool noOffset, Encoding encoder)
		{
			string strReturn = "";

			ArrayList nameBytes = new ArrayList();
			byte curByte;
			
			if(encoder == null)
				encoder = Encoding.ASCII;

			if(!noOffset)
				binReader.BaseStream.Seek(offset, SeekOrigin.Begin);

			if(binReader.BaseStream.Position >= binReader.BaseStream.Length)
				return "";

			curByte = binReader.ReadByte();
			while( (curByte != (byte)0) && (binReader.BaseStream.Position < binReader.BaseStream.Length) )
			{	
				nameBytes.Add( curByte );
				curByte = binReader.ReadByte();

				if( curByte == (byte)0 )
				{
					bFoundTerminator = true;
				}
			}

			byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));
			strReturn = encoder.GetString(name,0,name.Length);

			return strReturn;
		}

		/// <summary>
		/// Internal helper method to extract a null-terminated UTF-16/UCS-2 strings from a binary reader
		/// </summary>
		/// <param name="binReader">reference to the binary reader</param>
		/// <param name="offset">offset in the stream</param>
		/// <param name="noOffset">true if the offset value should be used</param>
		/// <param name="encoder">encoder used for text encoding</param>
		/// <returns>An extracted string value</returns>
		internal static string ExtractUTF16String(ref BinaryReader binReader, int offset, bool noOffset, Encoding encoder)
		{
			string strReturn = "";

			ArrayList nameBytes = new ArrayList();
			byte curByte;
			int lastByte=-1;
			
			if(!noOffset)
				binReader.BaseStream.Seek(offset, SeekOrigin.Begin);

			if(binReader.BaseStream.Position >= binReader.BaseStream.Length)
				return "";

			if(encoder == null)
				encoder = Encoding.Unicode;

			curByte = binReader.ReadByte();
			int nCnt = 0;
			while( ((curByte != (byte)0) || (lastByte != 0) ) && (binReader.BaseStream.Position < binReader.BaseStream.Length) )
			{	
				nameBytes.Add( curByte );

				if(nCnt%2 == 0)
					lastByte = (int)curByte;

				curByte = binReader.ReadByte();

				nCnt++;
			}

			byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));
			strReturn = Encoding.Unicode.GetString(name,0,name.Length);

			// apply text encoding
			name = Encoding.Default.GetBytes(strReturn);
			strReturn = encoder.GetString(name,0,name.Length);

			return strReturn;
		}

		/// <summary>
		/// Internal helper for reading ENCINT encoded integer values
		/// </summary>
		/// <param name="binReader">reference to the reader</param>
		/// <returns>a long value</returns>
		internal static long ReadENCINT(ref BinaryReader binReader)
		{
			long nRet = 0;
			byte buffer = 0;
			int shift = 0;

			if(binReader.BaseStream.Position >= binReader.BaseStream.Length)
				return nRet;
			
			do
			{
				buffer = binReader.ReadByte();
				nRet |= ((long)((buffer & (byte)0x7F))) << shift;
				shift += 7;

			}while ( (buffer & (byte)0x80) != 0);

			return nRet;
		}

		/// <summary>
		/// Reads an s/r encoded value from the byte array and decodes it into an integer
		/// </summary>
		/// <param name="wclBits">a byte array containing all bits (contains only 0 or 1 elements)</param>
		/// <param name="s">scale param for encoding</param>
		/// <param name="r">root param for encoding</param>
		/// <param name="nBitIndex">current index in the wclBits array</param>
		/// <returns>Returns an decoded integer value.</returns>
		internal static int ReadSRItem(byte[] wclBits, int s, int r, ref int nBitIndex)
		{
			int nRet = 0;
			int q = r;

			int nPref1Cnt = 0;

			while( wclBits[nBitIndex++] == 1)
			{
				nPref1Cnt++;
			}

			if(nPref1Cnt == 0)
			{
				int nMask = 0;

				for(int nbits=0; nbits<q;nbits++)
				{
					nMask |= ( 0x01 & (int)wclBits[nBitIndex]) << (q-nbits-1);
					nBitIndex++;
				}

				nRet = nMask;
			} 
			else 
			{
				q += (nPref1Cnt-1);

				int nMask = 0;
				int nRMaxValue = 0;

				for(int nbits=0; nbits<q;nbits++)
				{
					nMask |= ( 0x01 & (int)wclBits[nBitIndex]) << (q-nbits-1);
					nBitIndex++;
				}

				for(int nsv=0; nsv<r; nsv++)
				{
					nRMaxValue = nRMaxValue << 1;
					nRMaxValue |= 0x1;
				}
	
				nRMaxValue++; // startvalue of s/r encoding with 1 prefixing '1'

				nRMaxValue *= (int) Math.Pow((double)2, (double)(nPref1Cnt-1));

				nRet = nRMaxValue + nMask;
			}

			return nRet;
		}
	}

    /// <summary>
    /// 
    /// </summary>
	public class BinaryReaderEx : BinaryReader
	{
		private long FilePos=0;
		private long FileLen=0;

        /// <summary>
        /// Initializes a new instance of the <see cref="BinaryReaderEx"/> class.
        /// </summary>
        /// <param name="input">The input.</param>
		public BinaryReaderEx(Stream input) : base(input)
		{
			FileLen=input.Length; 
		}

        /// <summary>
        /// Initializes a new instance of the <see cref="BinaryReaderEx"/> class.
        /// </summary>
        /// <param name="input">The supplied stream.</param>
        /// <param name="encoding">The character encoding.</param>
        /// <exception cref="T:System.ArgumentException">The stream does not support reading, the stream is null, or the stream is already closed. </exception>
        /// <exception cref="T:System.ArgumentNullException">
        /// 	<paramref name="encoding"/> is null. </exception>
		public BinaryReaderEx(Stream input, Encoding encoding): base (input,encoding)
		{
			FileLen=input.Length;      
		}


        /// <summary>
        /// Gets a value indicating whether this <see cref="BinaryReaderEx"/> is EOF.
        /// </summary>
        /// <value><c>true</c> if EOF; otherwise, <c>false</c>.</value>
		public bool EOF
		{
			get
			{
				return FilePos>=FileLen;
			}
		}

        /// <summary>
        /// Gets the percentage read.
        /// </summary>
        /// <value>The percentage read.</value>
		public int PercentageRead
		{
			get
			{
				int Percent=(int)((FilePos*100)/FileLen);
				return Percent;
			}
		}

        /// <summary>
        /// Gets the position.
        /// </summary>
        /// <value>The position.</value>
		public long Position
		{
			get
			{
				return FilePos;
			}
		}

        /// <summary>
        /// Gets the length.
        /// </summary>
        /// <value>The length.</value>
		public long Length
		{
			get
			{
				return FileLen;
			}
		}

        /// <summary>
        /// Closes the current reader and the underlying stream.
        /// </summary>
		public override void Close()
		{
			FilePos=0;
		}

        /// <summary>
        /// Reads characters from the underlying stream and advances the current position of the stream in accordance with the Encoding used and the specific character being read from the stream.
        /// </summary>
        /// <returns>
        /// The next character from the input stream, or -1 if no characters are currently available.
        /// </returns>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
		public override int Read()
		{
			FilePos+=1;
			return base.Read();
		}

        /// <summary>
        /// Reads <paramref name="count"/> bytes from the stream with <paramref name="index"/> as the starting point in the byte array.
        /// </summary>
        /// <param name="buffer">The buffer to read data into.</param>
        /// <param name="index">The starting point in the buffer at which to begin reading into the buffer.</param>
        /// <param name="count">The number of characters to read.</param>
        /// <returns>
        /// The number of characters read into <paramref name="buffer"/>. This might be less than the number of bytes requested if that many bytes are not available, or it might be zero if the end of the stream is reached.
        /// </returns>
        /// <exception cref="T:System.ArgumentException">The buffer length minus <paramref name="index"/> is less than <paramref name="count"/>. </exception>
        /// <exception cref="T:System.ArgumentNullException">
        /// 	<paramref name="buffer"/> is null. </exception>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        /// 	<paramref name="index"/> or <paramref name="count"/> is negative. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
		public override int Read(byte[] buffer, int index, int count)
		{
			FilePos+=count;
			return base.Read(buffer,index,count);
		}

        /// <summary>
        /// Read7s the bit encoded integer.
        /// </summary>
        /// <returns></returns>
		protected int Read7BitEncodedInteger()
		{
			int value=base.Read7BitEncodedInt();
			FilePos+=BaseStream.Position;
			return value;
		}

        /// <summary>
        /// Reads a Boolean value from the current stream and advances the current position of the stream by one byte.
        /// </summary>
        /// <returns>
        /// true if the byte is nonzero; otherwise, false.
        /// </returns>
        /// <exception cref="T:System.IO.EndOfStreamException">The end of the stream is reached. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
		public override bool ReadBoolean()
		{
			FilePos+=1;
			return base.ReadBoolean();
		}

        /// <summary>
        /// Reads the next byte from the current stream and advances the current position of the stream by one byte.
        /// </summary>
        /// <returns>
        /// The next byte read from the current stream.
        /// </returns>
        /// <exception cref="T:System.IO.EndOfStreamException">The end of the stream is reached. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
		public override byte ReadByte()
		{
			FilePos+=1;
			return base.ReadByte();
		}

        /// <summary>
        /// Reads <paramref name="count"/> bytes from the current stream into a byte array and advances the current position by <paramref name="count"/> bytes.
        /// </summary>
        /// <param name="count">The number of bytes to read.</param>
        /// <returns>
        /// A byte array containing data read from the underlying stream. This might be less than the number of bytes requested if the end of the stream is reached.
        /// </returns>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        /// 	<paramref name="count"/> is negative. </exception>
		public override byte[] ReadBytes(int count)
		{
			FilePos+=count;
			return base.ReadBytes(count);
		}

        /// <summary>
        /// Reads the next character from the current stream and advances the current position of the stream in accordance with the Encoding used and the specific character being read from the stream.
        /// </summary>
        /// <returns>
        /// A character read from the current stream.
        /// </returns>
        /// <exception cref="T:System.IO.EndOfStreamException">The end of the stream is reached. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
        /// <exception cref="T:System.ArgumentException">A surrogate character was read. </exception>
		public override char ReadChar()
		{
			FilePos+=1;
			return ReadChar();
		}

        /// <summary>
        /// Reads <paramref name="count"/> characters from the current stream, returns the data in a character array, and advances the current position in accordance with the Encoding used and the specific character being read from the stream.
        /// </summary>
        /// <param name="count">The number of characters to read.</param>
        /// <returns>
        /// A character array containing data read from the underlying stream. This might be less than the number of characters requested if the end of the stream is reached.
        /// </returns>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        /// 	<paramref name="count"/> is negative. </exception>
		public override char[] ReadChars(int count)
		{
			FilePos+=count;
			return base.ReadChars(count);
		}

        /// <summary>
        /// Reads an 8-byte floating point value from the current stream and advances the current position of the stream by eight bytes.
        /// </summary>
        /// <returns>
        /// An 8-byte floating point value read from the current stream.
        /// </returns>
        /// <exception cref="T:System.IO.EndOfStreamException">The end of the stream is reached. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
		public override double ReadDouble()		
		{
			FilePos+=8;
			return base.ReadDouble();			
		}

        /// <summary>
        /// Reads a 2-byte signed integer from the current stream and advances the current position of the stream by two bytes.
        /// </summary>
        /// <returns>
        /// A 2-byte signed integer read from the current stream.
        /// </returns>
        /// <exception cref="T:System.IO.EndOfStreamException">The end of the stream is reached. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
		public override short ReadInt16()
		{
			FilePos+=2;
			return base.ReadInt16();			
		}

        /// <summary>
        /// Reads a 4-byte signed integer from the current stream and advances the current position of the stream by four bytes.
        /// </summary>
        /// <returns>
        /// A 4-byte signed integer read from the current stream.
        /// </returns>
        /// <exception cref="T:System.IO.EndOfStreamException">The end of the stream is reached. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
		public override int ReadInt32()
		{
			FilePos+=4;
			return base.ReadInt32();			
		}

        /// <summary>
        /// Reads an 8-byte signed integer from the current stream and advances the current position of the stream by eight bytes.
        /// </summary>
        /// <returns>
        /// An 8-byte signed integer read from the current stream.
        /// </returns>
        /// <exception cref="T:System.IO.EndOfStreamException">The end of the stream is reached. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
		public override long ReadInt64()
		{
			FilePos+=8;
			return base.ReadInt64();			
		}

        /// <summary>
        /// Reads a signed byte from this stream and advances the current position of the stream by one byte.
        /// </summary>
        /// <returns>
        /// A signed byte read from the current stream.
        /// </returns>
        /// <exception cref="T:System.IO.EndOfStreamException">The end of the stream is reached. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
		public override sbyte ReadSByte()
		{
			FilePos+=1;
			return base.ReadSByte();			
		}

        /// <summary>
        /// Reads a 4-byte floating point value from the current stream and advances the current position of the stream by four bytes.
        /// </summary>
        /// <returns>
        /// A 4-byte floating point value read from the current stream.
        /// </returns>
        /// <exception cref="T:System.IO.EndOfStreamException">The end of the stream is reached. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
		public override float ReadSingle()
		{
			FilePos+=4;
			return base.ReadSingle();			
		}

        /// <summary>
        /// Reads a string from the current stream. The string is prefixed with the length, encoded as an integer seven bits at a time.
        /// </summary>
        /// <returns>The string being read.</returns>
        /// <exception cref="T:System.IO.EndOfStreamException">The end of the stream is reached. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
		public override string ReadString()	
		{
			string s=base.ReadString();
			FilePos=this.BaseStream.Position;
			return s;
		}

        /// <summary>
        /// Reads a 2-byte unsigned integer from the current stream using little-endian encoding and advances the position of the stream by two bytes.
        /// </summary>
        /// <returns>
        /// A 2-byte unsigned integer read from this stream.
        /// </returns>
        /// <exception cref="T:System.IO.EndOfStreamException">The end of the stream is reached. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
		public override ushort ReadUInt16()	
		{
			FilePos+=2;
			return base.ReadUInt16();			
		}

        /// <summary>
        /// Reads a 4-byte unsigned integer from the current stream and advances the position of the stream by four bytes.
        /// </summary>
        /// <returns>
        /// A 4-byte unsigned integer read from this stream.
        /// </returns>
        /// <exception cref="T:System.IO.EndOfStreamException">The end of the stream is reached. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
		public override  uint ReadUInt32()		
		{
			FilePos+=4;
			return base.ReadUInt32();			
		}

        /// <summary>
        /// Reads an 8-byte unsigned integer from the current stream and advances the position of the stream by eight bytes.
        /// </summary>
        /// <returns>
        /// An 8-byte unsigned integer read from this stream.
        /// </returns>
        /// <exception cref="T:System.IO.EndOfStreamException">The end of the stream is reached. </exception>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
        /// <exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
		public override ulong ReadUInt64()
		{
			FilePos+=8;
			return base.ReadUInt64();			
		}

        /// <summary>
        /// Seeks the specified offset.
        /// </summary>
        /// <param name="offset">The offset.</param>
        /// <param name="origin">The origin.</param>
        /// <returns></returns>
		public long Seek(long offset, SeekOrigin origin)
		{
			switch(origin)
			{
				case SeekOrigin.Begin:
					FilePos=offset;
					break;
				case SeekOrigin.Current:
					FilePos+=offset;
					break;

				case SeekOrigin.End:
					FilePos=FileLen-offset;
					break;
			}
			return this.BaseStream.Seek(offset,origin);
		}

        /// <summary>
        /// Extracts the string.
        /// </summary>
        /// <param name="offset">The offset.</param>
        /// <param name="noOffset">if set to <c>true</c> [no offset].</param>
        /// <param name="encoder">The encoder.</param>
        /// <returns></returns>
		public string ExtractString(int offset, bool noOffset, Encoding encoder)
		{
			string strReturn = "";
			
			if(encoder == null)
				encoder = Encoding.ASCII;

			if(!noOffset)
				Seek(offset, SeekOrigin.Begin);
			
			if (EOF)
				return "";

			ArrayList nameBytes = new ArrayList();
			byte curByte;
					
			curByte = ReadByte();
			while( (curByte != (byte)0) && !EOF )
			{	
				nameBytes.Add( curByte );
				curByte = ReadByte();
			}

			byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));
			strReturn = encoder.GetString(name,0,name.Length);

			return strReturn;
		}

        /// <summary>
        /// Extracts the string.
        /// </summary>
        /// <param name="length">The length.</param>
        /// <param name="offset">The offset.</param>
        /// <param name="noOffset">if set to <c>true</c> [no offset].</param>
        /// <param name="encoder">The encoder.</param>
        /// <returns></returns>
		public string ExtractString(int length, int offset, bool noOffset, Encoding encoder)
		{
			string strReturn = "";

			if(length == 0)
				return "";

			if(encoder == null)
				encoder = Encoding.ASCII;

			ArrayList nameBytes = new ArrayList();
			byte curByte;
			
			if(!noOffset)
				Seek(offset, SeekOrigin.Begin);

			if(EOF)
				return "";

			curByte = ReadByte();
			while( (curByte != (byte)0) && (nameBytes.Count < length) && (!EOF) )
			{	
				nameBytes.Add( curByte );

				if(nameBytes.Count < length)
					curByte = ReadByte();
			}

			byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));
			strReturn = encoder.GetString(name,0,name.Length);

			return strReturn;
		}


        /// <summary>
        /// Extracts the string.
        /// </summary>
        /// <param name="bFoundTerminator">if set to <c>true</c> [b found terminator].</param>
        /// <param name="offset">The offset.</param>
        /// <param name="noOffset">if set to <c>true</c> [no offset].</param>
        /// <param name="encoder">The encoder.</param>
        /// <returns></returns>
		public string ExtractString(ref bool bFoundTerminator, int offset, bool noOffset, Encoding encoder)
		{
			string strReturn = "";

			ArrayList nameBytes = new ArrayList();
			byte curByte;
			
			if(encoder == null)
				encoder = Encoding.ASCII;

			if(!noOffset)
				Seek(offset, SeekOrigin.Begin);

			if(EOF)
				return "";

			curByte = ReadByte();
			while( (curByte != (byte)0) && (!EOF) )
			{	
				nameBytes.Add( curByte );
				curByte = ReadByte();

				if( curByte == (byte)0 )
				{
					bFoundTerminator = true;
				}
			}

			byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));
			strReturn = encoder.GetString(name,0,name.Length);

			return strReturn;
		}


        /// <summary>
        /// Extracts the UT F16 string.
        /// </summary>
        /// <param name="offset">The offset.</param>
        /// <param name="noOffset">if set to <c>true</c> [no offset].</param>
        /// <param name="encoder">The encoder.</param>
        /// <returns></returns>
		public string ExtractUTF16String(int offset, bool noOffset, Encoding encoder)
		{
			string strReturn = "";

			ArrayList nameBytes = new ArrayList();
			byte curByte;
			int lastByte=-1;
			
			if(!noOffset)
				Seek(offset, SeekOrigin.Begin);

			if(EOF)
				return "";

			if(encoder == null)
				encoder = Encoding.Unicode;

			curByte = ReadByte();

			if (curByte==0xff)
			{
				long block=(FilePos>>12);
				Seek(((block+1)*0x0100),SeekOrigin.Begin);
				curByte = ReadByte();
			}

			int nCnt = 0;
			while( ((curByte != (byte)0) || (lastByte != 0) ) && (!EOF) )
			{	
				nameBytes.Add( curByte );

				if(nCnt%2 == 0)
					lastByte = (int)curByte;

				curByte = ReadByte();

				nCnt++;
			}

			byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));
			strReturn = Encoding.Unicode.GetString(name,0,name.Length);

			// apply text encoding
			name = Encoding.Default.GetBytes(strReturn);
			strReturn = encoder.GetString(name,0,name.Length);

			return strReturn;
		}
	}
}
